﻿#region Copyright RenGuiYou. All rights reserved.
//=====================================================
// NeatlyFrameWork
// Author:      RenGuiyou
// Feedback: 	mailto:750539605@qq.com
//=====================================================
#endregion

using System;
using UnityEngine;
using System.Collections.Generic;
using Neatly.UI;
using UnityEngine.EventSystems;
using UnityEngine.UI;

[RequireComponent(typeof(RectTransform))]
public class NScrollRect : NUIBehaviour, IPointerDownHandler, IPointerUpHandler, IBeginDragHandler, IDragHandler, IEndDragHandler, ICanvasElement
{
    public bool m_Horizontal; //水平移动
    public bool m_Vertical; //垂直移动
    public RectTransform m_Viewport; //显示
    public RectTransform m_Content; //内容
    private readonly float m_ClampedLength = 0; //夹的距离
    public RectTransform m_HeadPanel; //头部跟随Panel
    public RectTransform m_ChoosePanel; //Choose跟随Panel
    private bool m_OpenChoosePanel;
    private int m_ChooseIndex = -1;
    public RectTransform m_TopItem; //顶部Item
    public RectTransform m_BottomItem; //底部Item
    private Vector2 m_PointerStartLocalCursor = Vector2.zero;
    private Vector2 m_ContentStartPosition = Vector2.zero;
    private Bounds m_ContentBounds;
    private Bounds m_ViewBounds;
    private bool m_Dragging;
    private bool m_IsEnable;
    #region Content与ViewPort便捷属性
    /// Content的坐标
    private Vector2 ContentPosition
    {
        get => m_Content.anchoredPosition;
        set => m_Content.anchoredPosition = value;
    }

    /// Content宽度
    private float ContentWidth => m_Content.rect.width;
    /// Content高度
    private float ContentHeight => m_Content.rect.height;
    /// ViewPort宽度
    private float ViewWidth => m_Viewport.rect.width;
    /// ViewPort高度
    private float ViewHeight => m_Viewport.rect.height;
    private RectTransform viewRect => m_Viewport;
    #endregion
    #region 无限循环滚动属性
    private bool _useLoop; //使用Loop功能
    private int _loopIndex; //当前标记位
    private int _loopMaxCount; //循环最大数
    private int _loopCacheCount; //循环缓存数
    private bool _inBack; //是否在back中
    private List<RectTransform> _loopItems;

    //网格布局
    private GridLayoutGroup m_gridLayoutGroup;
    private int gridConstraintCount = 1;
    private Vector2 gridPadding = Vector2.zero;

    /// 最后一项高度
    private float LastLoopItemHeight => _loopItems[^1].rect.height;
    /// 第一项高度
    private float FirstLoopItemHeight => _loopItems[0].rect.height;
    /// 顶部Item高度
    private float TopItemHeight => m_TopItem ? m_TopItem.rect.height : 0;
    /// 底部Item高度
    private float BottomItemHeight => m_BottomItem ? m_BottomItem.rect.height : 0;
    /// 最后一项宽度
    private float LastLoopItemWidth => _loopItems[^1].rect.width;
    /// 第一项宽度
    private float FirstLoopItemWidth => _loopItems[0].rect.width;
    /// 最左边Item宽度
    private float TopItemWidth => m_TopItem ? m_TopItem.rect.width : 0;
    /// 最右边Item宽度
    private float BottomItemWidth => m_BottomItem ? m_BottomItem.rect.width : 0;
    public Action<int> onLoopFront;
    public Action<int> onLoopBack;
    public Action onDragBegin;
    public Action onDragEnd;
    public Action onDragging;
    public Action onPointerDown;
    private Vector2 _lastDistance; //最终距离

    private Vector2 InertiaDestPointVertical //纵向惯性目标点
    {
        get
        {
            Vector2 targetPos = _lastDistance * InertiaStep;
            if (targetPos.y > ViewHeight / 2)
            {
                targetPos.y = ViewHeight / 2;
            }
            if (targetPos.y < -ViewHeight / 2)
            {
                targetPos.y = -ViewHeight / 2;
            }
            return targetPos;
        }
    }

    private Vector2 InertiaDestPointHorizontal //横向惯性目标点
    {
        get
        {
            Vector2 targetPos = _lastDistance * InertiaStep;
            if (targetPos.x > ViewWidth / 2)
            {
                targetPos.x = ViewWidth / 2;
            }
            if (targetPos.x < -ViewWidth / 2)
            {
                targetPos.x = -ViewWidth / 2;
            }
            return targetPos;
        }
    }

    private const float InertiaStep = 5f; //惯性距离倍数
    private const float InertiaSpeed = 5f; //惯性速度
    private const float OutInertiaSpeed = 30f; //出界后
    private float _nowInertiaSpeed; //当前惯性
    private Vector2 _lastPoint = Vector2.zero; //最后的点
    private Vector2 _firstPoint = Vector2.zero; //最先的点
    private const float ElasticTime = 0.1f; //弹性
    #endregion
    #region 子Scroll事件
    private List<NScrollRect> m_ScrollList;
    private Action<PointerEventData> m_ScrollBeginDragAction;
    private Action<PointerEventData> m_ScrollDragAction;
    private Action<PointerEventData> m_ScrollEndDragAction;

    public void SetScrollBeginDragAction(Action<PointerEventData> action)
    {
        m_ScrollBeginDragAction = action;
    }

    public void SetScrollDragAction(Action<PointerEventData> action)
    {
        m_ScrollDragAction = action;
    }

    public void SetScrollEndDragAction(Action<PointerEventData> action)
    {
        m_ScrollEndDragAction = action;
    }

    public void AddScroll(NScrollRect scroll)
    {
        scroll.SetScrollBeginDragAction(OnBeginDrag);
        scroll.SetScrollDragAction(OnDrag);
        scroll.SetScrollEndDragAction(OnEndDrag);
    }
    #endregion

    protected override void Start()
    {
        Init();
    }

    private void Init()
    {
        //网格每份个数
        m_gridLayoutGroup = m_Content.gameObject.GetComponent<GridLayoutGroup>();
        if (m_gridLayoutGroup != null)
        {
            gridConstraintCount = m_gridLayoutGroup.constraintCount;
            gridPadding = m_gridLayoutGroup.spacing;
        }

        //释放参数
        if (m_TopItem) m_TopItem.SetAsFirstSibling();
        if (m_BottomItem) m_BottomItem.SetAsLastSibling();
    }

    public void OnPointerDown(PointerEventData eventData)
    {
        Clean();
        onPointerDown?.Invoke();
    }

    public void OnPointerUp(PointerEventData eventData)
    {
        m_Inertia = true;
        if (m_Dragging)
            onDragEnd?.Invoke();
        m_Dragging = false;
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        Clean();
        m_PointerStartLocalCursor = Vector2.zero;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(viewRect, eventData.position, eventData.pressEventCamera, out m_PointerStartLocalCursor);
        m_ContentStartPosition = m_Content.anchoredPosition;
        m_Dragging = true;
        m_ScrollBeginDragAction?.Invoke(eventData);
        onDragBegin?.Invoke();
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        UpdateBounds();
        Vector2 min = m_ContentBounds.min;
        Vector2 max = m_ContentBounds.max;
        if (m_Vertical)
        {
            if (max.y < m_ViewBounds.max.y || min.y > m_ViewBounds.min.y)
            {
                _nowInertiaSpeed = OutInertiaSpeed;
            }
            else
            {
                _nowInertiaSpeed = InertiaSpeed;
            }
        }
        if (m_Horizontal)
        {
            if (max.x < m_ViewBounds.max.x || min.x > m_ViewBounds.min.x)
            {
                _nowInertiaSpeed = OutInertiaSpeed;
            }
            else
            {
                _nowInertiaSpeed = InertiaSpeed;
            }
        }
        _lastPoint = Vector2.zero;
        _firstPoint = Vector2.zero;
        m_Inertia = true;
        m_Dragging = false;
        m_ScrollEndDragAction?.Invoke(eventData);
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(viewRect, eventData.position, eventData.pressEventCamera, out var localCursor))
            return;
        var pointerDelta = localCursor - m_PointerStartLocalCursor;
        Vector2 position = m_ContentStartPosition + pointerDelta;
        _lastDistance = position - ContentPosition;
        MoveDistance(_lastDistance);
        onDragging?.Invoke();
        m_ScrollDragAction?.Invoke(eventData);
    }

    /// <summary>
    /// 移动
    /// </summary>
    /// <param name="delta"></param>
    public bool MoveDistance(Vector2 delta)
    {
        UpdateBounds();
        bool border = false;
        Vector2 min = m_ContentBounds.min;
        Vector2 max = m_ContentBounds.max;
        if (!m_Horizontal)
        {
            delta.x = 0;
        }
        if (!m_Vertical)
        {
            delta.y = 0;
        }
        if (m_Vertical)
        {
            if (max.y + delta.y < m_ViewBounds.max.y - m_ClampedLength)
            {
                border = true;
            }
            else if (ViewHeight > ContentHeight)
            {
                if (max.y + delta.y > m_ViewBounds.max.y + m_ClampedLength)
                {
                    border = true;
                }
            }
            else if (min.y + delta.y > m_ViewBounds.min.y + m_ClampedLength)
            {
                border = true;
            }
        }
        if (m_Horizontal)
        {
            if (max.x + delta.x < m_ViewBounds.max.x - m_ClampedLength)
            {
                border = true;
            }
            else if (ViewWidth > ContentWidth)
            {
                if (max.x + delta.x > m_ViewBounds.max.x + m_ClampedLength)
                {
                    border = true;
                }
            }
            else if (min.x + delta.x > m_ViewBounds.min.x + m_ClampedLength)
            {
                border = true;
            }
        }
        Vector2 position = ContentPosition + delta;
        delta = CalculateOffset(delta);
        position += delta;
        if (delta.y != 0 && m_Vertical)
            position.y -= RubberDelta(delta.y, m_ViewBounds.size.y);
        if (delta.x != 0 && m_Horizontal)
            position.x -= RubberDelta(delta.x, m_ViewBounds.size.x);
        ContentPosition = position;
        ResetLoopPosition();
        return border;
    }

    private Vector2 CalculateOffset(Vector2 delta)
    {
        Vector2 offset = Vector2.zero;
        Vector2 min = m_ContentBounds.min;
        Vector2 max = m_ContentBounds.max;
        if (m_Vertical)
        {
            min.y += delta.y;
            max.y += delta.y;
            if (max.y < m_ViewBounds.max.y)
                offset.y = m_ViewBounds.max.y - max.y;
            else if (min.y > m_ViewBounds.min.y)
                offset.y = m_ViewBounds.min.y - min.y;
        }
        if (m_Horizontal)
        {
            min.x += delta.x;
            max.x += delta.x;
            if (max.x < m_ViewBounds.max.x)
                offset.x = m_ViewBounds.max.x - max.x;
            else if (min.x > m_ViewBounds.min.x)
                offset.x = m_ViewBounds.min.x - min.x;
        }
        return offset;
    }

    private static float RubberDelta(float overStretching, float viewSize)
    {
        return (1 - (1 / ((Mathf.Abs(overStretching) * 0.55f / viewSize) + 1))) * viewSize * Mathf.Sign(overStretching);
    }

    /// <summary>
    /// 初始化循环滚动
    /// </summary>
    /// <param name="loopItems"></param>
    /// <param name="curIndex"></param>
    public void InitLoop(RectTransform[] loopItems, int curIndex)
    {
        _loopIndex = curIndex - 1;
        _loopItems = new List<RectTransform>(loopItems);
        _loopCacheCount = _loopItems.Count;
        //初始化缓存里面的预制
        for (int i = 0; i < _loopCacheCount; i++)
        {
            if (onLoopFront != null && m_IsEnable)
            {
                // onLoopFront.Invoke(curIndex);
            }
            curIndex++;
        }
#if UNITY_EDITOR
        for (int i = 0; i < _loopCacheCount; i++)
        {
            _loopItems[i].gameObject.name = "item" + (i + 1);
        }
#endif
        if (_loopIndex == 0)
        {
            ContentPosition = Vector2.zero;
            m_ContentStartPosition = Vector2.zero;
        }
    }

    public void SetIndex(int index)
    {
        m_Inertia = false;
        m_Content.SetAnchoredPositionOne(0);
        _loopIndex = index - 1;
    }

    public int GetIndex()
    {
        return _loopIndex;
    }

    /// <summary>
    /// 重置循环滚动
    /// </summary>
    /// <param name="loopItems"></param>
    public void ResetLoop(RectTransform[] loopItems)
    {
        _loopItems = new List<RectTransform>(loopItems);
        _loopCacheCount = _loopItems.Count;
#if UNITY_EDITOR
        for (int i = 0; i < _loopCacheCount; i++)
        {
            _loopItems[i].gameObject.name = "item" + (i + 1);
        }
#endif
    }

    /// 改变当前标记位
    public void AddCurrentIndex(int addCount)
    {
        _loopIndex += addCount;
    }

    /// 设置循环滚动最大数值
    public void SetLoopMax(int loopMax)
    {
        _loopMaxCount = loopMax;
        _useLoop = _loopItems.Count < loopMax;
    }

    /// 获取循环滚动最大数值
    public int GetLoopMax(GameObject go)
    {
        int maxCount = 0;
        if (go)
        {
            RectTransform tran = go.GetComponent<RectTransform>();
            if (tran)
                maxCount = Mathf.CeilToInt(m_Viewport.rect.height / tran.rect.height);
        }
        return maxCount;
    }

    /// 检测当前状态是否达到需要重置Item项
    public void ResetLoopPosition()
    {
        if (!_useLoop) return;
        UpdateBounds();
        Vector2 min = m_ContentBounds.min;
        Vector2 max = m_ContentBounds.max;
        if (m_Vertical)
        {
            if (_loopIndex + _loopCacheCount < _loopMaxCount && m_ViewBounds.min.y - min.y < LastLoopItemHeight + BottomItemHeight &&
                max.y - m_ViewBounds.max.y > FirstLoopItemHeight)
            {
                VerticalUp();
                for (int i = 0; i < gridConstraintCount; i++)
                {
                    _loopIndex++;
                    if (onLoopFront != null && m_IsEnable)
                    {
                        onLoopFront.Invoke(_loopIndex + _loopCacheCount);
                    }
                }
            }
            else if (_loopIndex > 0 && max.y - m_ViewBounds.max.y < FirstLoopItemHeight + TopItemHeight)
            {
                VerticalDown();
                for (int i = 0; i < gridConstraintCount; i++)
                {
                    if (onLoopBack != null && m_IsEnable)
                    {
                        onLoopBack.Invoke(_loopIndex);
                    }
                    _loopIndex--;
                }
            }
            if (m_HeadPanel)
            {
                Vector2 offset = new Vector2(0, m_HeadPanel.rect.height);
                if (_loopIndex > 0)
                {
                    m_HeadPanel.gameObject.SetActive(false);
                    ContentPosition -= offset;
                    m_ContentStartPosition -= offset;
                }
                else
                {
                    m_HeadPanel.gameObject.SetActive(true);
                    m_HeadPanel.SetAsFirstSibling();
                    ContentPosition += offset;
                    m_ContentStartPosition += offset;
                }
            }
            ResetChoosePanel();
        }
        if (m_Horizontal)
        {
            if (_loopIndex + _loopCacheCount < _loopMaxCount && m_ViewBounds.min.x - min.x > LastLoopItemWidth + BottomItemWidth && max.x - m_ViewBounds.max.x < FirstLoopItemWidth)
            {
                HorizontalLeft();
                for (int i = 0; i < gridConstraintCount; i++)
                {
                    _loopIndex++;
                    if (onLoopFront != null && m_IsEnable)
                    {
                        onLoopFront.Invoke(_loopIndex + _loopCacheCount);
                    }
                }
            }
            else if (_loopIndex > 0 && max.x - m_ViewBounds.max.x > FirstLoopItemWidth + TopItemWidth)
            {
                HorizontalRight();
                for (int i = 0; i < gridConstraintCount; i++)
                {
                    if (onLoopBack != null && m_IsEnable)
                    {
                        onLoopBack.Invoke(_loopIndex);
                    }
                    _loopIndex--;
                }
            }
            if (m_HeadPanel)
            {
                Vector2 offset = new Vector2(m_HeadPanel.rect.width, 0);
                if (_loopIndex > 0)
                {
                    m_HeadPanel.gameObject.SetActive(false);
                    ContentPosition -= offset;
                    m_ContentStartPosition -= offset;
                }
                else
                {
                    m_HeadPanel.gameObject.SetActive(true);
                    m_HeadPanel.SetAsFirstSibling();
                    ContentPosition += offset;
                    m_ContentStartPosition += offset;
                }
            }
        }
    }

    public void SetChooseIndex(int index)
    {
        m_ChooseIndex = index;
        m_ChoosePanel.gameObject.SetActive(false);
        ResetChoosePanel();
    }

    private void ResetChoosePanel()
    {
        if (m_ChooseIndex >= 0)
        {
            Vector2 offset = new Vector2(0, m_ChoosePanel.rect.height);
            if (m_ChooseIndex < _loopIndex)
            {
                if (m_ChoosePanel.gameObject.activeInHierarchy)
                {
                    m_ChoosePanel.gameObject.SetActive(false);
                    ContentPosition -= offset;
                    m_ContentStartPosition -= offset;
                }
            }
            else if (m_ChooseIndex >= _loopItems.Count + _loopIndex)
            {
                if (!m_ChoosePanel.gameObject.activeInHierarchy)
                {
                    m_ChoosePanel.gameObject.SetActive(true);
                    m_ChoosePanel.SetAsLastSibling();
                }
            }
            else if (_loopIndex <= m_ChooseIndex - _loopItems.Count)
            {
                m_ChoosePanel.gameObject.SetActive(false);
            }
            else
            {
                if (!m_ChoosePanel.gameObject.activeInHierarchy)
                {
                    m_ChoosePanel.gameObject.SetActive(true);
                    int lastIndex = m_ChoosePanel.GetSiblingIndex();
                    int newIndex = _loopItems[m_ChooseIndex - _loopIndex].GetSiblingIndex();
                    if (newIndex < lastIndex)
                    {
                        newIndex++;
                    }
                    m_ChoosePanel.SetSiblingIndex(newIndex - 1);
                }
            }
        }
    }

    /// <summary>
    /// 向上拖拽(Item下移)
    /// </summary>
    private void VerticalUp()
    {
        RectTransform rt = _loopItems[0];
        for (int i = 0; i < gridConstraintCount; i++)
        {
            rt = _loopItems[0];
            if (m_BottomItem)
                rt.SetSiblingIndex(m_Content.childCount - 2);
            else
                rt.SetAsLastSibling();
            _loopItems.RemoveAt(0);
            _loopItems.Add(rt);
        }
        Vector2 offset = new Vector2(0, rt.rect.height + gridPadding.y);
        ContentPosition -= offset;
        m_ContentStartPosition -= offset;
    }

    /// <summary>
    /// 向下拖拽(Item上移)
    /// </summary>
    private void VerticalDown()
    {
        int lastIndex = _loopItems.Count - 1;
        RectTransform rt = _loopItems[lastIndex];
        for (int i = 0; i < gridConstraintCount; i++)
        {
            rt = _loopItems[lastIndex];
            if (m_TopItem)
                rt.SetSiblingIndex(1);
            else
                rt.SetAsFirstSibling();
            _loopItems.RemoveAt(lastIndex);
            _loopItems.Insert(0, rt);
        }
        Vector2 offset = new Vector2(0, rt.rect.height + gridPadding.y);
        ContentPosition += offset;
        m_ContentStartPosition += offset;
    }

    /// <summary>
    /// 向左拖拽(Item右移)
    /// </summary>
    private void HorizontalLeft()
    {
        RectTransform rt = _loopItems[0];
        for (int i = 0; i < gridConstraintCount; i++)
        {
            rt = _loopItems[0];
            if (m_BottomItem)
                rt.SetSiblingIndex(m_Content.childCount - 2);
            else
                rt.SetAsLastSibling();
            _loopItems.RemoveAt(0);
            _loopItems.Add(rt);
        }
        Vector2 offset = new Vector2(rt.rect.width + gridPadding.x, 0);
        ContentPosition += offset;
        m_ContentStartPosition += offset;
    }

    /// <summary>
    /// 向右拖拽(Item左移)
    /// </summary>
    private void HorizontalRight()
    {
        int lastIndex = _loopItems.Count - 1;
        RectTransform rt = _loopItems[lastIndex];
        for (int i = 0; i < gridConstraintCount; i++)
        {
            rt = _loopItems[lastIndex];
            if (m_TopItem)
                rt.SetSiblingIndex(1);
            else
                rt.SetAsFirstSibling();
            _loopItems.RemoveAt(lastIndex);
            _loopItems.Insert(0, rt);
        }
        Vector2 offset = new Vector2(rt.rect.width + gridPadding.x, 0);
        ContentPosition -= offset;
        m_ContentStartPosition -= offset;
    }

    private void UpdateBounds()
    {
        var rect = viewRect.rect;
        m_ViewBounds = new Bounds(rect.center, rect.size);
        m_ContentBounds = GetBounds();
        if (m_Content == null)
            return;
        Vector3 contentSize = m_ContentBounds.size;
        Vector3 contentPos = m_ContentBounds.center;
        Vector3 excess = m_ViewBounds.size - contentSize;
        if (excess.x > 0)
        {
            contentPos.x -= excess.x * (m_Content.pivot.x - 0.5f);
            contentSize.x = m_ViewBounds.size.x;
        }
        if (excess.y > 0)
        {
            contentPos.y -= excess.y * (m_Content.pivot.y - 0.5f);
            contentSize.y = m_ViewBounds.size.y;
        }
        m_ContentBounds.size = contentSize;
        m_ContentBounds.center = contentPos;
    }

    private readonly Vector3[] m_Corners = new Vector3[4];

    private Bounds GetBounds()
    {
        if (m_Content == null)
            return new Bounds();
        var vMin = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
        var vMax = new Vector3(float.MinValue, float.MinValue, float.MinValue);
        var toLocal = viewRect.worldToLocalMatrix;
        m_Content.GetWorldCorners(m_Corners);
        for (int j = 0; j < 4; j++)
        {
            Vector3 v = toLocal.MultiplyPoint3x4(m_Corners[j]);
            vMin = Vector3.Min(v, vMin);
            vMax = Vector3.Max(v, vMax);
        }
        var bounds = new Bounds(vMin, Vector3.zero);
        bounds.Encapsulate(vMax);
        return bounds;
    }

    private UITweenImp _ltDescrVertical; //垂直归位动画.
    private UITweenImp _ltDescrHorizontal; //水平归位动画.

    /// <summary>
    /// 归位动画
    /// </summary>
    public void TweenBack(bool b_refresh = true)
    {
        _inBack = true;
        Clean();
        UpdateBounds();
        Vector2 min = m_ContentBounds.min;
        Vector2 max = m_ContentBounds.max;
        if (m_Vertical)
        {
            if (max.y < m_ViewBounds.max.y)
            {
                float distance = m_ViewBounds.max.y - max.y + ContentPosition.y;
                _ltDescrVertical = UITween.MoveY(m_Content, distance, ElasticTime);
            }
            else if (ViewHeight > ContentHeight)
            {
                if (max.y > m_ViewBounds.max.y)
                {
                    float distance = m_ViewBounds.max.y - max.y + ContentPosition.y;
                    _ltDescrVertical = UITween.MoveY(m_Content, distance, ElasticTime);
                }
                else
                {
                    _inBack = false;
                    return;
                }
            }
            else if (min.y > m_ViewBounds.min.y)
            {
                float distance = m_ViewBounds.min.y - min.y + ContentPosition.y;
                _ltDescrVertical = UITween.MoveY(m_Content, distance, ElasticTime);
            }
            else
            {
                if (b_refresh)
                {
                    m_Inertia = true;
                }
                _inBack = false;
                return;
            }
            if (!b_refresh) return;
        }
        if (m_Horizontal)
        {
            if (max.x < m_ViewBounds.max.x)
            {
                float distance = m_ViewBounds.max.x - max.x + ContentPosition.x;
                _ltDescrHorizontal = UITween.MoveX(m_Content, distance, ElasticTime);
            }
            else if (ViewWidth > ContentWidth)
            {
                if (max.x > m_ViewBounds.max.x)
                {
                    float distance = m_ViewBounds.max.x - max.x + ContentPosition.x;
                    _ltDescrHorizontal = UITween.MoveX(m_Content, distance, ElasticTime);
                }
                else
                {
                    _inBack = false;
                }
            }
            else if (min.x > m_ViewBounds.min.x)
            {
                float distance = m_ViewBounds.min.x - min.x + ContentPosition.x;
                _ltDescrHorizontal = UITween.MoveX(m_Content, distance, ElasticTime);
            }
            else
            {
                if (b_refresh)
                {
                    m_Inertia = true;
                }
                _inBack = false;
            }
        }
    }

    private bool m_Inertia;

    void LateUpdate()
    {
        if (!m_IsEnable || m_Dragging) return;
        if (m_Inertia)
        {
            if (Mathf.Approximately(_nowInertiaSpeed, OutInertiaSpeed))
            {
                TweenBack();
                m_Inertia = false;
                return;
            }
            Vector2 _inertiaDestPoint = m_Vertical ? InertiaDestPointVertical : (m_Horizontal ? InertiaDestPointHorizontal : Vector2.zero);
            _firstPoint = Vector2.Lerp(_firstPoint, _inertiaDestPoint, _nowInertiaSpeed * Time.deltaTime);
            Vector2 moveOffset = _firstPoint - _lastPoint;
            bool border = MoveDistance(moveOffset);
            _lastPoint = _firstPoint;
            if ((_firstPoint - _inertiaDestPoint).magnitude < 1 || border)
            {
                TweenBack();
                m_Inertia = false;
            }
        }
        else
        {
            if (!_inBack)
            {
                TweenBack(false);
            }
        }
    }

    protected override void OnEnable()
    {
        m_IsEnable = true;
        CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
    }

    protected override void OnDisable()
    {
        CanvasUpdateRegistry.UnRegisterCanvasElementForRebuild(this);
        m_IsEnable = false;
        m_Inertia = false;
        LayoutRebuilder.MarkLayoutForRebuild(transform.rectTransform());
    }

    protected override void OnCanvasHierarchyChanged()
    {
        //        bool isShow = CheckIsShow();
        //        if (isShow)
        //        {
        //            m_IsEnable = true;
        //        }
        //        else
        //        {
        //            m_IsEnable = false;
        //            m_Inertia = false;
        //        }
    }

    public void Rebuild(CanvasUpdate executing)
    {
    }

    public void LayoutComplete()
    {
    }

    public void GraphicUpdateComplete()
    {
    }

    /// <summary>
    /// 清理(动画与惯性)
    /// </summary>
    private void Clean()
    {
        m_Inertia = false;
        if (_ltDescrVertical != null)
        {
            UITween.Cancel(gameObject);
            _ltDescrVertical = null;
        }
        if (_ltDescrHorizontal != null)
        {
            UITween.Cancel(gameObject);
            _ltDescrHorizontal = null;
        }
    }
}